/*
 * pruebaLeerSector.c
 *
 *  Created on: 09/09/2011
 *      Author: Federico Croci
 */
#define SOCK_PATH "echo_socket"
#include "tiposPlanificador.h"
#include "cola.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>//para las constantes
#include "operacionesSectores.h"
#include <sys/mman.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/un.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>




int main() {
	struct config datosConfig;
	struct datosPlanif *datosPlanificacion;
	datosPlanificacion=(struct datosPlanif*) malloc(sizeof(struct datosPlanif));
	//FORK
	pid_t consola_pid; //para el pid de los procesos en la relacion MAIN y consola
	int valorRetorno, i, b;
	char * const listaParametros[] =
			{
					"/home/utn_so/Desarrollo/Workspace/Consola_Disco/Release/Consola_Disco",
					NULL };
	//Socket UNIX
	int descriptorSocket, descriptorSocket_consola;
	struct sockaddr_un dirLocal, dirConsola;
	int len;
	//MMAP
	long size;
	datosConfig.rutaArchivoDisco="/home/utn_so/Escritorio/fat32.disk";
	FILE *f = fopen(datosConfig.rutaArchivoDisco, "rb");
	if (f)
	{
	   fseek(f, 0 ,SEEK_END);
	   size = ftell(f);
	   fclose(f);
	}
	int descriptorArchivo;
	if ((descriptorArchivo = open(datosConfig.rutaArchivoDisco,	O_RDWR)) == -1) {
		 perror("open");// si open() devuelve -1 es por que no se puedo abrir el archivo.
		 }
	datosPlanificacion->regionDeMemoria = mmap(0, size, PROT_WRITE, MAP_SHARED,
				descriptorArchivo, 0); //(caddr_t) 0 es para que el SO decida la ubicacion en memoria que va a tener

	//Division de flujo PADRE/HIJO
	switch (consola_pid = fork()) { //HAGO EL fork() Y SWITCH DEL VALOR DE RETORNO DEL fork()

	case -1: { // CASO DE ERROR DEL fork()
		perror("fork"); /* si fork() devuelve -1 es por que dio error */
		exit(1); /* Proceso padre hace exit */
	}

	case 0: { //ESTO ES LO QUE HACE EL PROCESO HIJO          para el proceso hijo consola_pid va a valer 0
		execv(
				"/home/utn_so/Desarrollo/Workspace/Consola_Disco/Release/Consola_Disco",
				listaParametros); //ejecuta la consola
		exit(1); //si llega aca hubo error en la consola
	}

	default: { //ESTO ES LO QUE HACE EL PROCESO PADRE              para el proceso padre consola_pid va a tenes el pid del hijo
		//CREO SOCKET UNIX
		if ((descriptorSocket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
			perror("creacion de socket UNIX");
			exit(1);
		}
		dirLocal.sun_family = AF_UNIX;
		strcpy(dirLocal.sun_path, SOCK_PATH);
		unlink(dirLocal.sun_path); //para borrar el nombre del archivo del filesystem, pero el proceso lo puede seguir usando al archivo
		len = strlen(dirLocal.sun_path) + sizeof(dirLocal.sun_family);
		if (bind(descriptorSocket, (struct sockaddr*) &dirLocal, len) == -1) {
			perror("bind socket unix local");
			exit(1);
		}
		//LISTEN PARA CONSOLA
		listen(descriptorSocket, 1); //escucha clientes (maximo 1)
		//ACCEPT CONSOLA
		len = sizeof(struct sockaddr_in);
		descriptorSocket_consola = accept(descriptorSocket,
				(struct sockaddr*) &dirConsola, (void*) &len); //acepta conexiones  BLOQUEANTE
		//fin socket unix ACA YA TENGO LISTO descriptorSocket_consola PARA USAR

		pthread_t productor_tid,consumidor_tid;//CREACION THREADS PARA PLANIFICAR
		sem_init(datosPlanificacion->pedidosDisponibles,0,0);//El valor inicial del semaforo es 0.

		if(pthread_create(&productor_tid,NULL,(void*)&productorPedidos,(void*)datosPlanificacion)){
			perror("No se puedo crear el THREAD,");
			return EXIT_FAILURE;//si llega aca no se puedo crear el thread.
		}
		if(pthread_create(&consumidor_tid,NULL,(void*)&consumidorPedidos,(void*)datosPlanificacion)){
			perror("No se puedo crear el THREAD,");
			return EXIT_FAILURE;//si llega aca no se puedo crear el thread.
		}
		/*{ //bloque de prueba, reenvia los strings que me mandan
			char str[100];
			int done = 0, n;
			do {
				n = recv(descriptorSocket_consola,str, 100, 0);
				if (n <= 0) {
					if (n < 0)
						perror("recv");
					done = 1;
				}

				if (!done)
					if (send(descriptorSocket_consola, str, n, 0) < 0) {
						perror("send");
						done = 1;
					}
			} while (!done);
		}*/

		pthread_join(productor_tid,NULL);//JOIN threads de planificacion
		pthread_join(consumidor_tid,NULL);

		wait(&valorRetorno); //WAIT CONSOLA  con wait() me quedo esperando a que termine el hijo y meto el return del hijo en valorRetorno BLOQUEANTE

		close(descriptorSocket);//CLOSE SOCKET CONSOLA

		munmap(datosPlanificacion->regionDeMemoria, size);
		close(descriptorArchivo);

		break;
	}
	}//SWITCH
	return 0;
}


